/**
 * 数据交互模块---基于文件的
 * 负责数据交互，对题库进行增删查改等操作
 * 根据questions.list文件加载所有题目到内存中
 * 对外提供访问数据的接口
 */
#pragma once
#include <iostream>
#include<string>
#include<unordered_map>
#include"../Comm/Detail.hpp"
#include<memory>
#include<cassert>
#include<vector>
#include<fstream>


namespace OnlineOJ
{
    namespace ns_Model
    {
        // 题目信息
        struct Question
        {
            std::string number; // 题号
            std::string title;  // 题目标题
            std::string star;   // 难度：简单、中等、困难
            int cpu_limit;      // cpu限制(s)
            int mem_limit;      // 内存限制(KB)
            std::string desc;   // 题目描述
            std::string header; // 预设代码
            std::string tail;   // 测试用例
        };
        using QuestionPtr=std::shared_ptr<Question>;
        const std::string questions_list="./questions/questions.list";//默认题目列表信息的路径
        const std::string questions_path="./questions/";//默认题目信息目录
        //数据交互
        class Model
        {
        public:
            Model()
            {
                assert(LoadQuestinsList());
            }
            //加载questions/questions.list文件中的题目信息到_questions中
            bool LoadQuestinsList(const std::string& ql=questions_list)
            {
                std::ifstream in(ql);
                if(!in.is_open())
                {
                    LOG(FATAL,"加载题库失败！\n");
                    return false;
                }
                //读取文件内容并解析
                std::string line;
                while(std::getline(in,line))//每次读取一行
                {
                    std::vector<std::string> result;
                    int ret=ns_Detail::StringUtil::SplitString(line,result," ");
                    if(ret!=5)
                    {
                        LOG(WARNING,"部分题目加载失败！\n");
                        continue;
                    }
                    //构建题目信息对象
                    auto sq=std::make_shared<Question>();
                    sq->number=result[0];
                    sq->title=result[1];
                    sq->star=result[2];
                    sq->cpu_limit=std::stoi(result[3]);
                    sq->mem_limit=std::stoi(result[4]);

                    std::string question_path=questions_path;//题目相关信息所在的目录
                    question_path+=sq->number;//题目相关信息所在路径
                    question_path+="/";

                    //读取题目相关信息
                    ns_Detail::FileUtil::ReadFile(question_path+"desc.txt",sq->desc,true);
                    ns_Detail::FileUtil::ReadFile(question_path+"header.cpp",sq->header,true);
                    ns_Detail::FileUtil::ReadFile(question_path+"tail.cpp",sq->tail,true);

                    _questions.insert({sq->number,sq});
                }
                in.close();
                LOG(INFO,"题库加载成功！\n");
                return true;
            }
            //获取所有题目到questions中
            bool GetAllQuestions(std::vector<QuestionPtr>& questions)
            {
                if(_questions.size()==0)
                {
                    LOG(ERROR,"获取题库失败！\n");
                    return false;
                }

                for(const auto& q:_questions)
                {
                    questions.push_back(q.second);
                }
                return true;
            }

            //获取一个题目到question中
            bool GetOneQuestion(const std::string& num,QuestionPtr& question)
            {
                auto it=_questions.find(num);
                if(it==_questions.end())
                {
                    LOG(ERROR,"%s号题目获取失败！\n",num.c_str());
                    return false;
                }
                question=it->second;
                return true;
            }
        private:
            std::unordered_map<std::string,QuestionPtr> _questions;//题库，题号与题目信息的映射
        };
    }
}